﻿using Emgu.CV.Structure;
using Emgu.CV;
using System;
using System.Drawing;

namespace CrazyMVSamLibrary.Function
{
    internal class Transforms
    {
        private int mTargetLength;

        public Transforms(int target_length)
        {
            this.mTargetLength = target_length;
        }

        private void GetPreprocessShape(int oldw, int oldh, int long_side_length, ref int neww, ref int newh)
        {
            float scale = long_side_length * 1.0f / Math.Max(oldh, oldw);
            float newht = oldh * scale;
            float newwt = oldw * scale;
            neww = (int)(newwt + 0.5);
            newh = (int)(newht + 0.5);
        }

        public float[] ApplyImage(Mat image, int orgw, int orgh)
        {
            int neww = 0;
            int newh = 0;
            GetPreprocessShape(orgw, orgh, this.mTargetLength, ref neww, ref newh);
            Mat resized = new Mat();
            CvInvoke.Resize(image, resized, new Size(neww, newh));
            Image<Bgr, float> resizedImage = resized.ToImage<Bgr, float>();
            resized.Dispose();
            MCvScalar mean = new MCvScalar(), stddev = new MCvScalar();
            CvInvoke.MeanStdDev(resizedImage, ref mean, ref stddev);
            float[,,] data = resizedImage.Data;
            float[] transformedImg = new float[3 * this.mTargetLength * this.mTargetLength];
            for (int i = 0; i < neww; i++)
            {
                for (int j = 0; j < newh; j++)
                {
                    int index = j * this.mTargetLength + i;
                    transformedImg[index] = (data[j, i, 0] - (float)mean.V0) / (float)stddev.V0;
                    transformedImg[this.mTargetLength * this.mTargetLength + index] = (data[j, i, 1] - (float)mean.V1) / (float)stddev.V1;
                    transformedImg[2 * this.mTargetLength * this.mTargetLength + index] = (data[j, i, 2] - (float)mean.V2) / (float)stddev.V2;
                }
            }
            resizedImage.Dispose();
            return transformedImg;
        }

        public PointPromotion ApplyCoords(PointPromotion org_point, int orgw, int orgh)
        {
            int neww = 0;
            int newh = 0;
            this.GetPreprocessShape(orgw, orgh, this.mTargetLength, ref neww, ref newh);
            PointPromotion newpointp = new PointPromotion(org_point.m_Optype);
            float scalx = 1.0f * neww / orgw;
            float scaly = 1.0f * newh / orgh;
            newpointp.X = (int)(org_point.X * scalx);
            newpointp.Y = (int)(org_point.Y * scaly);
            return newpointp;
        }

        public BoxPromotion ApplyBox(BoxPromotion org_box, int orgw, int orgh)
        {
            BoxPromotion box = new BoxPromotion();
            PointPromotion left = this.ApplyCoords(org_box.mLeftUp, orgw, orgh);
            PointPromotion lefrightt = this.ApplyCoords(org_box.mRightBottom, orgw, orgh);
            box.mLeftUp = left;
            box.mRightBottom = lefrightt;
            return box;
        }
    }
}